package com.dogegg.lbblog.intercept;

import com.dogegg.lbblog.support.LogRecordContext;
import com.dogegg.lbblog.support.UserDetail;
import com.dogegg.lbblog.support.UserDetailService;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.expression.AnnotatedElementKey;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.context.expression.CachedExpressionEvaluator;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.TypedValue;

import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class LogRecordCachedExpressionEvaluator extends CachedExpressionEvaluator {

    public static final String RESULT_VARIABLE = "result";
    public static final String ERR_MSG_VARIABLE = "err_msg";
    public static final String CONTEXT_VARIABLE = "variable";
    public static final String USER_VARIABLE = "user";

    private final Map<ExpressionKey, Expression> contentCache = new ConcurrentHashMap<>(64);
    private final Map<ExpressionKey, Expression> conditionCache = new ConcurrentHashMap<>(64);

    public LogRecordEvaluationContext createEvaluationContext
            (Method method, Object[] args, Object targetClass, Object ret, Throwable throwable, BeanFactory beanFactory, UserDetailService userService){
        LogRecordEvaluationContext evaluationContext = new LogRecordEvaluationContext(TypedValue.NULL, method, args, getParameterNameDiscoverer());
        evaluationContext.setVariable(RESULT_VARIABLE,ret);
        evaluationContext.setVariable(CONTEXT_VARIABLE,LogRecordContext.getVariableValues());
        if(throwable != null){
            evaluationContext.setVariable(ERR_MSG_VARIABLE,throwable.getMessage());
        }
        if (beanFactory != null) {
            evaluationContext.setBeanResolver(new BeanFactoryResolver(beanFactory));
        }
        UserDetail user = userService.getUser();
        if(user != null){
            evaluationContext.setVariable(USER_VARIABLE,user);
        }
        return evaluationContext;
    }

    public String content(String expression, AnnotatedElementKey methodKey, EvaluationContext evalContext){
        return getExpression(this.contentCache, methodKey, expression).getValue(evalContext,String.class);
    }

    public boolean condition(String expression, AnnotatedElementKey methodKey, EvaluationContext evalContext){
        return (Boolean.TRUE.equals(getExpression(this.conditionCache, methodKey, expression).getValue(
                evalContext, Boolean.class)));
    }


}
